/*
 * Copyright (c) 2007-2012, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
/*
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id: SerializerFactory.java,v 1.2.4.1 2005/09/15 08:15:24 suresh_emailid Exp $
 */
package com.sun.org.apache.xml.internal.serializer;

import java.util.Hashtable;
import java.util.Properties;

import javax.xml.transform.OutputKeys;

import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
import com.sun.org.apache.xml.internal.serializer.utils.Utils;
import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
import org.xml.sax.ContentHandler;

/**
 * This class is a public API, it is a factory for creating serializers.
   *
   * The properties object passed to the getSerializer() method should be created by
   * the OutputPropertiesFactory. Although the properties object
   * used to create a serializer does not need to be obtained
   * from OutputPropertiesFactory,
   * using this factory ensures that the default key/value properties
   * are set for the given output "method".
   *
   * <p>
   * The standard property keys supported are: "method", "version", "encoding",
   * "omit-xml-declaration", "standalone", doctype-public",
   * "doctype-system", "cdata-section-elements", "indent", "media-type".
   * These property keys and their values are described in the XSLT recommendation,
   * see {@link <a href="http://www.w3.org/TR/1999/REC-xslt-19991116"> XSLT 1.0 recommendation</a>}
   *
   * <p>
   * The value of the "cdata-section-elements" property key is a whitespace
   * separated list of elements. If the element is in a namespace then
   * value is passed in this format: {uri}localName
   *
   * <p>
   * The non-standard property keys supported are defined in {@link OutputPropertiesFactory}.
   *
   * @see OutputPropertiesFactory
   * @see Method
   * @see Serializer
   */
public final class SerializerFactory {
    /**
     * This constructor is private just to prevent the creation of such an object.
     */

    private SerializerFactory() {

    }

    /**
     * Associates output methods to default output formats.
     */
    private static Hashtable m_formats = new Hashtable();

    /**
     * Returns a serializer for the specified output method. The output method
     * is specified by the value of the property associated with the "method" key.
     * If no implementation exists that supports the specified output method
     * an exception of some type will be thrown.
     * For a list of the output "method" key values see {@link Method}.
     *
     * @param format The output format, minimally the "method" property must be set.
     * @return A suitable serializer.
     * @throws IllegalArgumentException if method is
     * null or an appropriate serializer can't be found
     * @throws Exception if the class for the serializer is found but does not
     * implement ContentHandler.
     * @throws WrappedRuntimeException if an exception is thrown while trying to find serializer
     */
    public static Serializer getSerializer(Properties format) {
        Serializer ser;

        try {
            String method = format.getProperty(OutputKeys.METHOD);

            if (method == null) {
                String msg = Utils.messages.createMessage(MsgKey.ER_FACTORY_PROPERTY_MISSING, new Object[] { OutputKeys.METHOD });
                throw new IllegalArgumentException(msg);
            }

            String className = format.getProperty(OutputPropertiesFactory.S_KEY_CONTENT_HANDLER);

            if (null == className) {
                // Missing Content Handler property, load default using OutputPropertiesFactory
                Properties methodDefaults = OutputPropertiesFactory.getDefaultMethodProperties(method);
                className = methodDefaults.getProperty(OutputPropertiesFactory.S_KEY_CONTENT_HANDLER);
                if (null == className) {
                    String msg = Utils.messages.createMessage(MsgKey.ER_FACTORY_PROPERTY_MISSING, new Object[] { OutputPropertiesFactory.S_KEY_CONTENT_HANDLER });
                    throw new IllegalArgumentException(msg);
                }

            }

            Class cls = ObjectFactory.findProviderClass(className, true);

            // _serializers.put(method, cls);

            Object obj = cls.newInstance();

            if (obj instanceof SerializationHandler) {
                // this is one of the supplied serializers
                ser = (Serializer) cls.newInstance();
                ser.setOutputFormat(format);
            } else {
                /*
                 *  This  must be a user defined Serializer.
                 *  It had better implement ContentHandler.
                 */
                if (obj instanceof ContentHandler) {

                    /*
                     * The user defined serializer defines ContentHandler,
                     * but we need to wrap it with ToXMLSAXHandler which
                     * will collect SAX-like events and emit true
                     * SAX ContentHandler events to the users handler.
                     */
                    className = SerializerConstants.DEFAULT_SAX_SERIALIZER;
                    cls = ObjectFactory.findProviderClass(className, true);
                    SerializationHandler sh = (SerializationHandler) cls.newInstance();
                    sh.setContentHandler((ContentHandler) obj);
                    sh.setOutputFormat(format);

                    ser = sh;
                } else {
                    // user defined serializer does not implement
                    // ContentHandler, ... very bad
                    throw new Exception(Utils.messages.createMessage(MsgKey.ER_SERIALIZER_NOT_CONTENTHANDLER, new Object[] { className }));
                }

            }
        } catch (Exception e) {
            throw new com.sun.org.apache.xml.internal.serializer.utils.WrappedRuntimeException(e);
        }

        // If we make it to here ser is not null.
        return ser;
    }
}
